﻿using Proto;

namespace sgf.server
{
    public class ActorCore
    {
        protected ActorSystem _system = new();

        public Dictionary<Type, PID> Pids = new();

        protected static ActorCore core;

        public ActorCore()
        {
            core = this;
            _system.EventStream.Subscribe<DeadLetterEvent>(deadLetterEvent =>
            {
                LogMgr.Error($"DeadLetterEvent: {deadLetterEvent.Message} {deadLetterEvent.Pid}");
            });
        }

        public static ActorCore Core()
        {
            return core;
        }
        
        public  ActorSystem System() => _system;

        public PID AddActorBus<T>() where T : IBusActor, new() 
        {
            var pid = _system.Root.Spawn(Props.FromProducer(() => new T()));
            Pids[typeof(T)] = pid;
            return pid;
        }

        public async Task<PID> AddActorBusAsync<T>() where T : IBusActor, new()
        {
            var pid = _system.Root.Spawn(Props.FromProducer(() => new T()));
            Pids[typeof(T)] = pid;
            await pid.SendAsync<CheckStartReq, CheckStartResp>(new CheckStartReq());
            return pid;
        }

        public static PID? GetPid(Type type)
        {
            core.Pids.TryGetValue(type, out var outPid);
            return outPid;
        }

        public static void Send(PID pid, object message, PID? sender = null)
        {
            core._system.Root.Request(pid, message, sender);
        }

        public static void SendAsync<T>(PID pid, object message,
            CancellationToken cancellationToken = new CancellationToken())
        {
            core._system.Root.RequestAsync<T>(pid, message, cancellationToken);
        }

        public static async Task<TV> SendAsync<T, TV>(PID pid, T message, CancellationToken cancellationToken = new())
            where T : IRequestMsg where TV : IResponseMsg
        {
            return await core._system.Root.RequestAsync<TV>(pid, message, cancellationToken);
        }
    }
}